<?php

namespace app\common;

class IpLocation
{

    private $client_ip = null;

    private $client_location = null;

    private $ipAddress = [];

    private $locationName = [];

    //获取客户端IP
    function __construct()
    {
        $path = __DIR__;
        $ips = file_get_contents($path . '/ip.json');
        $this->ipAddress = json_decode($ips, true);
        $this->getIp();
        $this->getLocation();

    }

    /**
     * 获取 地域名简称
     * @return array
     */
    public function getName(){
        $en = array_unique(array_column($this->ipAddress, 'en'));
        $province = array_unique(array_column($this->ipAddress, 'province'));
        foreach ($en as $key=>$value){
            foreach ($province as $k =>$item){
                if ($key == $k){
                    $this->locationName[$value] = $item;
                }
            }
        }
        unset($key,$k);
        return $this->locationName;
    }

    /**
     * 获取客户端ip
     * @return $this
     */
    private function getIp()
    {
        if (isset($_SERVER["HTTP_CLIENT_IP"]) && strcasecmp($_SERVER["HTTP_CLIENT_IP"], "unknown")) {
            $ip = $_SERVER["HTTP_CLIENT_IP"];
        } else {
            if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) && strcasecmp($_SERVER["HTTP_X_FORWARDED_FOR"], "unknown")) {
                $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
            } else {
                if (isset($_SERVER["REMOTE_ADDR"]) && strcasecmp($_SERVER["REMOTE_ADDR"], "unknown")) {
                    $ip = $_SERVER["REMOTE_ADDR"];
                } else {
                    if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'],
                            "unknown")
                    ) {
                        $ip = $_SERVER['REMOTE_ADDR'];
                    } else {
                        $ip = "unknown";
                    }
                }
            }
        }
        $this->client_ip = $ip;
        unset($ip);
        return $this;
    }

    /**
     * 根据客户端ip判断客户端省份
     * @param $ip
     * @param $ipArr
     * @return $this
     */
    private function getLocation()
    {
        if (!$this->client_ip) {
            return null;
        }
        if (!$this->ipAddress) {
            return null;
        }
        $ip = explode('.', $this->client_ip);
        foreach ($ip as $item) {
            if ($item > 255 || $item < 0) {
                echo 'ip 地址错误';
                exit;
            }
        }
        $locationArr = [];
        //判断ip 头
        foreach ($this->ipAddress as $value) {
            $start = explode('.', $value['start']);
            if ($ip[0] != $start[0]) {
                continue;
            } else {
                $locationArr[] = $value;
            }
        }
        if (!$locationArr) {
            echo '国外IP';
            exit;
        }

        $target = [];
        $clientIpStr = $this->ipToStr($this->client_ip);
        foreach ($locationArr as $key=> $item){
            $start = $this->ipToStr($item['start']);
            $end = $this->ipToStr($item['end']);
            $startDiffLen = $this->diffLen($clientIpStr,$start);
            $endDiffLen = $this->diffLen($clientIpStr,$end);
            if ($startDiffLen <= $endDiffLen){
                $target[$key]  = $startDiffLen;
            }else{
                $target[$key] = $endDiffLen;
            }
        }
        $minTarget = min(array_values($target));
        $key = array_search($minTarget,$target);
        $this->client_location =  $locationArr[$key];
        return $this;
    }

    /**
     * 计算两个IP之间得差值
     */
    private function diffLen($ip1,$ip2){
        return abs(bcsub($ip1,$ip2));
    }

    /**
     *
     * @param $ip
     * @return string
     */
    private function ipToStr($ip){
        $ipArr = explode('.',$ip);
        $str = '';
        foreach ($ipArr as $item){
            if (strlen($item) < 3){
                $item =   str_pad($item,'3','0',STR_PAD_LEFT);
            }
            $str.=$item;
        }
        return $str;
    }
    /**
     *
     * @return null
     */
    public function getClientIp()
    {
        if (!$this->client_ip || $this->client_ip == 'unknown') {
            return null;
        }
        return $this->client_ip;
    }

    public function getClientInfo()
    {
        return $this->client_location;
    }
}